package javaproject;

import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.media.j3d.*;
import javax.swing.*;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import sun.audio.AudioStream;

public class Main{
    public static void main(String[] args)
    {
	//System.out.println("&& "+args[0]+" , "+args[1]+" , "+args[2]);
        AI.confidence_multiplier[0] = 1;
        AI.confidence_multiplier[1] = 1;
        AI.confidence_multiplier[2] = 0.5;//Double.valueOf(args[0]);
        AI.confidence_multiplier[3] = 0.3;//Double.valueOf(args[1]);
        AI.confidence_multiplier[4] = 0.65;//Double.valueOf(args[2]);
        new Config();
	JFrame frame = new JFrame("新感覺彈幕系pixel風體感3D貪食蛇");
	frame.add(new Graph3D());
	frame.setSize(Config.width,Config.height);
	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	frame.setVisible(true);
        
    }
}

class Graph3D extends JApplet{
    //------------------configURATION------------------//
    private boolean pause = false;
    private boolean nextPause = false;
    public int direction = Snake.NONE;

    //AI
    private AI ai;
    
    //牆壁
    private double wallSpeed;
    private BlockWall currentWall = null;
    private BlockWall wallY;
    private BlockWall wallZ;
    private BlockFrameWall frameWallY;
    private BlockFrameWall frameWallZ;


    //分數
    private Text3D T_score;
    private int score = 0;
    private int totalTime = 0;	//遊戲歷經時間(ms)
    private int difficulty = 0;
    private Text3D T_time;

    TransformGroup TextG;
    Transform3D transArrow;
    TransformGroup arrowGroup;
        
    //生命
    private Raster lifes;
    private Text3D T_life;

    //顯示agents
    private Text3D T_agentWall;
    private Text3D T_agentClose;
    private Text3D T_agentBlank;
    private Text3D T_agentCentral;
    private Text3D T_agentCapsule;
    private Raster star;
    
    //showoff
    private Timer showoff;
    private int showoffTime;
    //Keyboard
    private KeyboardHandler keyboardHandler;
    //Rotate
    private Rotator rotator;
    private boolean isRotating = false;
    //public boolean autoRotate = true;
    public boolean autoRotate = false;

    private Debugger debugger;
    private Canvas3D canvas3D;
    private SpinGroup objSpin;
    private BranchGroup objRoot;
    private BranchGroup objContainer;

    //Snake
    private Snake snake;
    private Bullets bullets;
    private Capsules capsules;
    /*
    private Plane planeZ;
    private Plane planeX;
    private PlaneFrame planeFrameZ;
    private PlaneFrame planeFrameX;
     *
     */

    private Timer timer;

    //sound
    private AudioStream bgm;

    private FPSCounter fpsCounter;

    Graph3D()
    {
	wallSpeed = Config.initSpeed;

        if(Config.AA)
            System.setProperty("j3d.implicitAntialiasing", "true");
        debugger = new Debugger();
        setLayout(new BorderLayout());

	canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
        simpleU.getViewingPlatform().setNominalViewingTransform();
        objRoot = createSceneGraph();
        simpleU.addBranchGraph(objRoot);
	add("Center", canvas3D);

	//Wiimote
	//wiimoteManager = new WiimoteHandler(this, debugger);
	//Keyboard
	keyboardHandler = new KeyboardHandler(this, snake, ai);
        canvas3D.addKeyListener(keyboardHandler);

	//Timer
        timer = new Timer(Config.refreshRate, proceed);

	//Rotator
	rotator = new Rotator(this, objSpin, debugger);
    }
    private BranchGroup createSceneGraph() {
        //objRoot->objAdjust->objSpin->objContainer->blocks.......

        objRoot = new BranchGroup();
        //objRoot.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

	//設定分數字型
	T_score = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "0", new Point3f(Config.scoreX,Config.scoreY,Config.scoreZ));
	T_score.setCapability(Text3D.ALLOW_STRING_WRITE);
        T_time = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "0", new Point3f(Config.timeX,Config.timeY,Config.timeZ));
        T_time.setCapability(Text3D.ALLOW_STRING_WRITE);
        
        //生命
        T_life = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "0", new Point3f(Config.lifeX,Config.lifeY,Config.lifeZ));
        T_life.setString("X "+String.valueOf(Config.initLength));
        T_life.setCapability(Text3D.ALLOW_STRING_WRITE);

        //顯示agents
        T_agentWall = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "Border Repulsion", new Point3f(Config.agentWallX,Config.agentWallY,Config.agentWallZ));
        T_agentClose = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "Close Quarter Dodge", new Point3f(Config.agentCloseX,Config.agentCloseY,Config.agentCloseZ));
        T_agentBlank = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "Spacious Room Preference", new Point3f(Config.agentBlankX,Config.agentBlankY,Config.agentBlankZ));
        T_agentCentral = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "Homesick", new Point3f(Config.agentCentralX,Config.agentCentralY,Config.agentCentralZ));
        T_agentCapsule = new Text3D(new Font3D(new Font("微軟正黑體", Font.PLAIN, 1), new FontExtrusion(new java.awt.geom.Line2D.Double(0,0,0.05,0))), "Gluttony", new Point3f(Config.agentCapsuleX,Config.agentCapsuleY,Config.agentCapsuleZ));
        
        lifes = null;
        try {
            BufferedImage rawImg = ImageIO.read(new java.io.File("img/vic_s.png"));
            ImageComponent2D img = new ImageComponent2D(ImageComponent.FORMAT_RGBA, rawImg);
            lifes = new Raster(new Point3f(Config.lifeIconX,Config.lifeIconY,Config.lifeIconZ), Raster.RASTER_COLOR, 0,0,rawImg.getWidth(),rawImg.getHeight(),img,null);

        } catch (IOException e) {
        }
        TransparencyAttributes lifeTrApp = new TransparencyAttributes( );
        lifeTrApp.setTransparency( 0f );
        lifeTrApp.setTransparencyMode( TransparencyAttributes.BLENDED );
        Appearance lifeApp = new Appearance( );
        lifeApp.setTransparencyAttributes( lifeTrApp );
        
        star = null;
        try {
            BufferedImage rawImg = ImageIO.read(new java.io.File("img/star.gif"));
            ImageComponent2D img = new ImageComponent2D(ImageComponent.FORMAT_RGBA, rawImg);
            star = new Raster(new Point3f(Config.starX,Config.starY,Config.starZ), Raster.RASTER_COLOR, 0,0,rawImg.getWidth(),rawImg.getHeight(),img,null);

        } catch (IOException e) {
        }
        TransparencyAttributes starTrApp = new TransparencyAttributes( );
        starTrApp.setTransparency( 0f );
        starTrApp.setTransparencyMode( TransparencyAttributes.BLENDED );
        Appearance starApp = new Appearance( );
        starApp.setTransparencyAttributes( starTrApp );
        
        
	Transform3D transScore = new Transform3D();
	transScore.setScale(0.035);
	TextG = new TransformGroup(transScore);
        TextG.addChild(new Shape3D(T_score));
        TextG.addChild(new Shape3D(T_time));
        TextG.addChild(new Shape3D(T_life));
        TextG.addChild(new Shape3D(T_agentWall));
        TextG.addChild(new Shape3D(T_agentClose));
        TextG.addChild(new Shape3D(T_agentBlank));
        TextG.addChild(new Shape3D(T_agentCentral));
        TextG.addChild(new Shape3D(T_agentCapsule));
        TextG.addChild(new Shape3D(lifes,lifeApp));
        
        transArrow = new Transform3D();
        transArrow.setTranslation(new Vector3d(0,0,0));
        arrowGroup = new TransformGroup(transArrow);
        arrowGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        arrowGroup.addChild(new Shape3D(star,starApp));
        TextG.addChild(arrowGroup);

	objRoot.addChild(TextG);

        objSpin = new SpinGroup();                      //整體旋轉
        objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objContainer = new BranchGroup();
        objContainer.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

        //導引線
        Appearance glineApp = new Appearance();
        glineApp.setLineAttributes(new LineAttributes(Config.lineWidth, LineAttributes.PATTERN_SOLID, true));
        glineApp.setColoringAttributes(new ColoringAttributes(Config.guideLineColor,ColoringAttributes.NICEST));

        //外框
        Appearance boundingApp = new Appearance();
        boundingApp.setColoringAttributes(new ColoringAttributes(Config.frameColor, ColoringAttributes.NICEST));
        boundingApp.setLineAttributes(new LineAttributes(Config.lineWidth, LineAttributes.PATTERN_SOLID, true));
        BlockFrame boundingBox = new BlockFrame(new float[]{Config.boundingW, Config.boundingH, Config.boundingD}, new double[]{0,0,0},boundingApp, Config.frameTrans);
        objContainer.addChild(boundingBox.getTransformGroup());

        //蛇
        snake = new Snake(this, objContainer, debugger);

        //子彈
        bullets = new Bullets(objContainer, debugger);
	bullets.initBullets(objContainer);

	//Capsule
	capsules = new Capsules();
	capsules.generateCapsules(objContainer);

        /*
        //牆壁
        Appearance wallApp = new Appearance();
        wallApp.setColoringAttributes(new ColoringAttributes(Config.wallColor, ColoringAttributes.NICEST));
        wallApp.setRenderingAttributes(new RenderingAttributes(true, true, 0, RenderingAttributes.GREATER));
        Appearance wallFrameApp = new Appearance();
        wallFrameApp.setLineAttributes(new LineAttributes(Config.lineWidth, LineAttributes.PATTERN_SOLID, true));
        wallFrameApp.setColoringAttributes(new ColoringAttributes(0,0,0, ColoringAttributes.NICEST));
        wallY = new BlockWall(new float[]{Config.blockW,Config.blockH,Config.blockD}, new int[]{Config.edgeLength/2,Config.edgeLength/2,Config.edgeLength/2}, Config.multiplier, BlockWall.NORMAL_Y, wallApp, 1, 0.1f*Config.blockW, new int[][]{{-1,-1,-1},{1,1,1}});
	wallZ = new BlockWall(new float[]{Config.blockW,Config.blockH,Config.blockD}, new int[]{Config.edgeLength/2,Config.edgeLength/2,Config.edgeLength/2}, Config.multiplier, BlockWall.NORMAL_Z, wallApp, 1, 0.1f*Config.blockW, new int[][]{{-1,-1,-1},{1,1,1}});
	//丟到畫面外夠遠處
        wallY.moveTo(0, Config.outOfScreen, 0);
	wallZ.moveTo(0, 0, Config.outOfScreen);
        frameWallY = new BlockFrameWall(new float[]{Config.blockW,Config.blockH,Config.blockD}, new int[]{Config.edgeLength/2,Config.edgeLength/2,Config.edgeLength/2}, Config.multiplier, BlockFrameWall.NORMAL_Y,wallFrameApp, 1, new int[][]{{-1,-1,-1},{1,1,1}});
	frameWallZ = new BlockFrameWall(new float[]{Config.blockW,Config.blockH,Config.blockD}, new int[]{Config.edgeLength/2,Config.edgeLength/2,Config.edgeLength/2}, Config.multiplier, BlockFrameWall.NORMAL_Z,wallFrameApp, 1, new int[][]{{-1,-1,-1},{1,1,1}});
	//丟到畫面外夠遠處
        frameWallY.moveTo(0, Config.outOfScreen, 0);
	frameWallZ.moveTo(0, 0, Config.outOfScreen);
        objContainer.addChild(wallY.getTransformGroup());
	objContainer.addChild(wallZ.getTransformGroup());
        objContainer.addChild(frameWallY.getTransformGroup());
	objContainer.addChild(frameWallZ.getTransformGroup());
        * 
        */

        //燈光
        PointLight lightA = new PointLight(new Color3f(0.4f,0.4f,0.4f), new Point3f(0,0,0), new Point3f(0.8f,0,0));
        lightA.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), 2.0));
        objContainer.addChild(lightA);

	//背景
	try {
	    TextureLoader BKLoader = new TextureLoader(new File("./img/BK8.jpg").toURI().toURL(), null);
	    Appearance appBK = new Appearance();
	    appBK.setTexture(BKLoader.getTexture());
	    Sphere BK = new Sphere((float)Config.radius-0.5f, Primitive.GENERATE_TEXTURE_COORDS | Primitive.GENERATE_NORMALS_INWARD, 64, appBK);
	    Transform3D transBK = new Transform3D();
            Transform3D transBKtemp = new Transform3D();
	    transBK.rotY(Math.PI/180*60);
            transBKtemp.rotZ(Math.PI/180*50);
            transBK.mul(transBKtemp);
            transBKtemp.rotX(Math.PI/180*180);
            transBK.mul(transBKtemp);
	    TransformGroup BKG = new TransformGroup(transBK);
	    BKG.addChild(BK);
	    objContainer.addChild(BKG);
	} catch (MalformedURLException ex) {
	    Logger.getLogger(Graph3D.class.getName()).log(Level.SEVERE, null, ex);
	}

        //AI
        ai = new AI(bullets.bulletList, capsules.inScreen, snake, debugger);    
        
        //校準角度、位置
	final TransformGroup objAdjust = new TransformGroup();
	objAdjust.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objAdjust.addChild(objContainer);
        objRoot.addChild(objAdjust);

	//開場動畫
	final Vic_Viper vic_viper = (Vic_Viper)snake.blocks.getLast();
        //第一段的長度(開始撥音樂)
	final int stage1 = 200;
        //第二段的長度
	final int stage2 = 250;
	final Vector3d offsetV = new Vector3d();
	showoffTime = 0;
	showoff = new Timer(Config.refreshRate, new ActionListener()
	{
	    public void actionPerformed(ActionEvent e) {
		showoffTime++;
		if(showoffTime == stage1)
		    bgm = SoundEX.play(SoundEX.BGM);
		if(showoffTime < stage2)
		{
		    double t = (double)showoffTime/stage2;
                    //用指數函數可以達成一開始快速變化，再慢慢減慢的效果
                    //x是一個遞增但漸慢的函數
                    //而x和y之間的關係是一元二次方程式(拋物線)
                    double temp_x = -Math.pow(t, 2)+2*Math.pow(t, 1);
                    double x = -Math.pow(t, 2.5)+2*Math.pow(t, 1);
                    double y = Math.pow(temp_x, 12);
		    double factor = Math.pow(t, 0.5);
		    double factor2 = Math.pow(t, 0.35);
		    double factor3 = Math.pow(t, 0.1);
		    vic_viper.moveTo((-1+x)*3, (-1+y)*1.1, 30*(1-factor3));
		    vic_viper.rotYto(8*Math.PI*factor);

		    Transform3D axis = new Transform3D();
		    Transform3D axisTemp = new Transform3D();
		    axis.rotX(Config.rotX*factor2);
		    axisTemp.rotZ(Config.rotZ*factor2);
		    axis.mul(axisTemp);
		    Transform3D offset = new Transform3D();
		    offsetV.x = Config.posOffsetX*factor2;
		    offsetV.y = Config.posOffsetY*factor2;
		    offsetV.z = Config.posOffsetZ*factor2;
		    offset.set(offsetV);
		    axis.mul(offset);
		    Transform3D scaler = new Transform3D();
		    scaler.setScale(Config.scale);
		    axis.mul(scaler);
		    objAdjust.setTransform(axis);
		}
		else			//開場完後初始化各物件
		{
		    showoff.stop();
		    Iterator it = bullets.bulletList.iterator();
		    while(it.hasNext())
			((Bullet)it.next()).randomize();

		    Iterator it2 = capsules.inScreen.iterator();
		    while(it2.hasNext())
			((Capsule)it2.next()).randomize();

		    continueProceeding();
		}
	    }
	});
	showoff.setRepeats(true);
	showoff.start();

        //FPS
        if(Config.FPS)
        {
            fpsCounter = new FPSCounter();
            fpsCounter.setWarmupTime(10);
            fpsCounter.setLoopCount(200);
            fpsCounter.setMaxLoops(1000);

            fpsCounter.setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0),100.0));
            objRoot.addChild(fpsCounter);
        }

        objRoot.compile();
        return objRoot;
    }
    private void changeDifficulty()
    {
	if(score/Config.difficultyLevel > difficulty+1)
	{
	    if(difficulty == 0 && Config.showWall)
	    {
		currentWall = wallY;
		int hole[][] = wallY.generateHole();
		wallY.setHole(hole);
		frameWallY.setHole(hole);
		wallY.moveTo(0, Config.blockD*Config.d, 0);
		frameWallY.moveTo(0, Config.blockD*Config.d, 0);
	    }
	    difficulty++;
	    wallSpeed = Config.initSpeed*(1+difficulty*Config.wallSpeedStep);
            //每次增加difficulty個子彈 
            double r = Math.random();
            bullets.addBullets((int)Math.sqrt(difficulty), snake.getPosition(), Bullet.NORMAL_BULLET, true);
	}
    }
    public boolean isPaused()
    {
	return pause;
    }
    public void continueProceeding()
    {
	//canvas3D.setEnabled(true);
	timer.start();
	if(isRotating)
	    rotator.continueRotate();
	pause = false;
        nextPause = false;
    }
    public void shortPause()
    {
	//pause = false;
        nextPause = true;
        timer.start();
    }
    public void stopProceeding()
    {
	pause = true;
	if(rotator.stopRotate())
	    isRotating = true;
	//canvas3D.setEnabled(false);
	timer.stop();
    }
    public void gameOver()
    {
	stopProceeding();
	SoundEX.stop(bgm);
        //System.out.println(AI.confidence_multiplier[2]+" , "+AI.confidence_multiplier[3]+" , "+AI.confidence_multiplier[4]);
        //System.out.println("score : "+score);
        //System.exit(0);
	
	Timer counter = new Timer(1000, new ActionListener()
	{
	    public void actionPerformed(ActionEvent e) {
		final JFrame frame = (JFrame)getParent().getParent().getParent().getParent();
		JDialog j = new JDialog(frame);
		j.setLocation(Config.width/2, Config.height/2);
		Box b = Box.createVerticalBox();
		b.add(Box.createGlue());
		b.add(new JLabel("最高分:"+score), "center");
		b.add(Box.createGlue());
		j.getContentPane().add(b, "Center");

		JPanel p2 = new JPanel();
		JButton ok = new JButton("Ok");
		p2.add(ok);
		j.getContentPane().add(p2, "South");
		j.add(b);

		j.setSize(100,100);
		j.setVisible(true);

		ok.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent evt) {
			System.exit(0);
		    }
		});
	    }
	});
	counter.setRepeats(false);
	counter.start();
        
    }
    ActionListener proceed = new ActionListener(){
        public void actionPerformed(ActionEvent event) {
            //改變難易度
            changeDifficulty();

            //分數
            totalTime++;
            score+= Math.pow(Math.E, Config.optionBonus*snake.options) * (1+Config.timeBonus*totalTime);
            T_score.setString("Score: "+String.valueOf(score));
            T_time.setString("Time: "+String.valueOf(totalTime));

            //剩餘命數
            T_life.setString("X "+String.valueOf(snake.options));
            


            //Wiimote旋轉
            /*
            if(wiimoteManager.rotateDirection != Rotator.NONE)   //先判斷十字鍵旋轉
                rotator.rotate(wiimoteManager.rotateDirection, Config.rotateStep);
            else
            {
                rotator.stopRotate();   //沒有小旋轉，才判斷大旋轉
                if(wiimoteManager.rotateActive && wiimoteManager.rotateEnabled)
                {
                    if(wiimoteManager.pitch < -Config.rotateThreshold)
                        rotator.rotate(Rotator.UP);
                    else if(wiimoteManager.pitch > Config.rotateThreshold)
                        rotator.rotate(Rotator.DOWN);
                    else if(wiimoteManager.roll < -Config.rotateThreshold)
                        rotator.rotate(Rotator.LEFT);
                    else if(wiimoteManager.roll > Config.rotateThreshold)
                        rotator.rotate(Rotator.RIGHT);
                }
            }
            * 
            */

            //AI control
            ai.proceed();

            //移動星星arrow
            if (AI.lastDecideAgent==0)
                transArrow.setTranslation(new Vector3d(0,-2.1,0));
            else if (AI.lastDecideAgent==1)
                transArrow.setTranslation(new Vector3d(0,-3.3,0));
            else if (AI.lastDecideAgent==2)
                transArrow.setTranslation(new Vector3d(0,-4.4,0));
            else if (AI.lastDecideAgent==3)
                transArrow.setTranslation(new Vector3d(0,-1,0));
            else if (AI.lastDecideAgent==4)
                transArrow.setTranslation(new Vector3d(0,0,0));
            arrowGroup.setTransform(transArrow);
            
            
            //Keyboard control, which has higher priority than AI control
            if(keyboardHandler.fixedRotate)
            {
                rotator.rotate(keyboardHandler.rotateDirection);
                keyboardHandler.fixedRotate = false;
                keyboardHandler.rotateDirection = Rotator.NONE;
            }
            else if(keyboardHandler.rotateDirection != Rotator.NONE)
                rotator.rotate(keyboardHandler.rotateDirection, Config.rotateStep);
            if(keyboardHandler.checkCheat())
                snake.cheat();

            //常時旋轉
            //if(autoRotate && !pause)
            //    rotator.rotate(Rotator.LEFT, Config.continuousRotateStep);

            //子彈
            if(Config.showBullet)
            {
                bullets.proceed(snake.getPosition());
                //debugger.update(debugger.T_custom8, bullets.bulletList.size());
            }

            //Capsules
            if(Config.showCapsule)
                capsules.proceed(totalTime);

            //蛇
            snake.proceed(direction, bullets, capsules, currentWall);

            //牆
            if(Config.showWall && currentWall != null)
            {
                if(currentWall == wallY)
                {
                    if(wallY.isEnd())
                    {
                        int[][] hole = wallY.generateHole();

                        wallY.moveTo(0, Config.outOfScreen, 0);
                        frameWallY.moveTo(0, Config.outOfScreen, 0);
                        wallY.setHole(hole);
                        frameWallY.setHole(hole);

                        wallZ.moveTo(0, 0, -Config.blockD*Config.d);
                        frameWallZ.moveTo(0, 0, -Config.blockD*Config.d);

                        currentWall = wallZ;
                    }
                    else
                    {
                        wallY.proceed(wallSpeed);
                        frameWallY.proceed(wallSpeed);
                    }
                }
                else
                {
                    if(wallZ.isEnd())
                    {
                        int[][] hole = wallZ.generateHole();

                        wallZ.moveTo(0, Config.outOfScreen, 0);
                        frameWallZ.moveTo(0, Config.outOfScreen, 0);
                        wallZ.setHole(hole);
                        frameWallZ.setHole(hole);

                        wallY.moveTo(0, Config.blockH*Config.h, 0);
                        frameWallY.moveTo(0, Config.blockH*Config.h, 0);

                        currentWall = wallY;
                    }
                    else
                    {
                        wallZ.proceed(-wallSpeed);
                        frameWallZ.proceed(-wallSpeed);
                    }
                }
            }
            if(nextPause)
            {
                timer.stop();
                nextPause = false;
            }
        }
    };
}
